#pragma once

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <string>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <functional>

#include "Comm.hpp"
#include "Log.hpp"
#include "Nocopy.hpp"
#include "LockGuard.hpp"
#include "InetAddr.hpp"
#include "Thread.hpp"
#include "ThreadPool.hpp"

const static int default_backlog = 5;
using task_t = function<void(int,InetAddr&)>;

class TcpServer;

class ThreadDate
{
public:
    ThreadDate(TcpServer* pts,int sockfd,const InetAddr& addr)
        :_sockfd(sockfd),_pts(pts),_addr(addr)
    {}

    int Sockfd()
    {
        return _sockfd;
    }

    InetAddr& GetAddr()
    {
        return _addr;
    }

    TcpServer* GetPTcpserver()
    {
        return _pts;
    }
    ~ThreadDate()
    {}
private:
    int _sockfd;
    TcpServer* _pts;
    InetAddr _addr;
};

class TcpServer : public Nocopy
{   
public:
    TcpServer(uint16_t port)
        :_port(port),_isrunning(false)
    {}

    void Init()
    {
        // 创建套接字
        _listensock = socket(AF_INET,SOCK_STREAM,0);
        if(_listensock < 0)
        {
            lg.LogMessage(Fatal,"create socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
            exit(Socket_err);
        }
        lg.LogMessage(Info , "create socket success , sockfd : %d\n",_listensock);

        int opt = 1;
        setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&opt,sizeof(opt));

        // 填充网络信息，并绑定
        struct sockaddr_in ServerSockaddr;
        ServerSockaddr.sin_family = AF_INET;
        ServerSockaddr.sin_port = htons(_port);
        ServerSockaddr.sin_addr.s_addr = INADDR_ANY;
        socklen_t ServerLen = sizeof(ServerSockaddr);

        int n = bind(_listensock , (struct sockaddr*)&ServerSockaddr,ServerLen);
        if(n < 0)
        {
            lg.LogMessage(Fatal,"bind socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
            exit(Bind_err);
        }
        lg.LogMessage(Info , "bind socket success , sockfd : %d\n",_listensock);

        // 将listensock调节为监听模式
        int m = listen(_listensock,default_backlog);
        if(m < 0)
        {
            lg.LogMessage(Fatal,"listen socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
            exit(Listen_err);
        }
        lg.LogMessage(Info , "listen socket success , sockfd : %d\n",_listensock);
    }

    // v1、v2、v3版本Service
    // void Service(int sockfd)
    // {
    //     char buffer[1024];
    //     while(true)
    //     {
    //         int n = read(sockfd,buffer,sizeof(buffer) - 1);
    //         if(n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "Client Say# " << buffer << std::endl;

    //             std::string response = buffer;
    //             int m = write(sockfd,response.c_str(),response.size());
                
    //         }
    //         else if(n == 0)
    //         {
    //             lg.LogMessage(Warning,"client quit\n");
    //             break;
    //         }
    //         else
    //         {
    //             lg.LogMessage(Fatal,"read socket error , errno : %d , error string : %s\n",errno,strerror(errno));
    //             break;
    //         }
    //     }
    // }

    // v4版本Service
    void Service(int sockfd,InetAddr& inetAddr)
    {
        char buffer[1024];
        while(true)
        {
            int n = read(sockfd,buffer,sizeof(buffer) - 1);
            if(n > 0)
            {
                buffer[n] = 0;
                std::cout << inetAddr.PrintDebug() << buffer << std::endl;

                std::string response = buffer;
                int m = write(sockfd,response.c_str(),response.size());
                
            }
            else if(n == 0)
            {
                lg.LogMessage(Warning,"client quit\n");
                break;
            }
            else
            {
                lg.LogMessage(Fatal,"read socket error , errno : %d , error string : %s\n",errno,strerror(errno));
                break;
            }
        }
    }

    static void* HandlerRoutine(void* arg)
    {
        // 使主线程与新线程分离，使得主线程不需要等待新线程终止
        pthread_detach(pthread_self());

        ThreadDate* td = (ThreadDate*)arg;
        td->GetPTcpserver()->Service(td->Sockfd(),td->GetAddr());

        // 关闭文件描述符，delete ThreadDate
        close(td->Sockfd());
        delete td;

        return nullptr;
    }

    void Start()
    {
        _isrunning = true;
        while(_isrunning)
        {
            // 获取连接
            struct sockaddr_in ClientSockaddr;
            socklen_t ClientLen = sizeof(ClientSockaddr);
            int sockfd = accept(_listensock,CONV(&ClientSockaddr),&ClientLen);

            if(sockfd < 0)
            {
                lg.LogMessage(Warning,"accept socket fail , errno : %d , error string : %s\n",errno,strerror(errno));
                break;
            }
            lg.LogMessage(Info , "accept socket success , get a new sockfd : %d\n",sockfd);

            // v3版本服务，忽略子进程退出时给父进程发送的信号
            signal(SIGCHLD,SIG_IGN);

            // 提供服务
            // v1版本，单进程版本
            // Service(sockfd);
            // close(sockfd);

            // v2版本，多进程版本 ，父进程负责接收连接，子进程(孙子进程)负责处理连接
            // 这里父进程和子进程需要关闭自己不需要的文件描述符
            // 防止多个客户端访问服务器时，导致父进程的文件描述符不够用的情况
            // int fd = fork();
            // if(fd < 0)
            // {
            //     lg.LogMessage(Fatal,"fork child process fail , errno : %d , error string : %s\n",errno,strerror(errno));
            //     break;
            // }
            // else if(fd == 0) // 子进程
            // {
            //     // 这里我们不想让父进程等待子进程退出
            //     // 我们创建一个孙子进程，子进程退出
            //     // 这样孙子进程变成了孤儿进程，被操作系统领养
            //     // 退出时，操作系统会回收孙子进程
            //     if(fork())  
            //         exit(0);

            //     Service(sockfd);
            //     close(sockfd);
                
            //     close(_listensock);
            // }
            // else // 父进程
            // {
            //     close(sockfd);
            // }

            // v3版本，多进程版本，忽略信号版本
            // 忽略子进程退出时给父进程发送的信号,父进程就不需要等待子进程退出了
            // int fd = fork();
            // if(fd < 0)
            // {
            //     lg.LogMessage(Fatal,"fork child process fail , errno : %d , error string : %s\n",errno,strerror(errno));
            //     break;
            // }
            // else if(fd == 0) // 子进程
            // {
            //     Service(sockfd);
            //     close(sockfd);
                
            //     close(_listensock);
            // }
            // else // 父进程
            // {
            //     close(sockfd);
            // }

            // v4版本，多线程版本
            // pthread_t pth;
            // ThreadDate* ptd = new ThreadDate(this,sockfd,InetAddr(ClientSockaddr));
            // pthread_create(&pth,nullptr,HandlerRoutine,ptd);
        }
    }

    ~TcpServer()
    {}

private:
    uint16_t _port;
    int _listensock;
    bool _isrunning;
};